<?php

namespace App\Controller\Center;

use App\Agent\RedisQueueAgent;
use App\Agent\SmsAgent;
use App\Constants\ErrorCode;
use App\Constants\RedisKey;
use App\Controller\InsideService\GameConfigInside;
use App\Controller\InsideService\GameListInside;
use App\Controller\InsideService\GameUserInside;
use App\Controller\InsideService\PaySenderInside;
use App\Model\QmGameAccount;
use App\Model\QmGameAccountVerify;
use App\Model\QmGameList;
use App\Model\QmGameSpecial;
use App\Model\QmGameVersion;
use App\Model\QmGameWxTask;
use App\Service\AliyunService;
use App\Service\QmGameService;
use App\Service\SlWechatService;
use App\Service\SmsService;
use App\Service\ToolService;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Guzzle\ClientFactory;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;
use Hyperf\HttpServer\Annotation\PostMapping;
use Hyperf\Utils\ApplicationContext;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

#[Controller(prefix: '/center')]
class GameVersionController extends BaseController {
    /**
     * @Inject
     * @var ClientFactory
     */
    protected ClientFactory $clientFactory;

    private array $serverStatus = [1, 2, 5, 6, 7];

    /**
     * 获取用户服务器列表
     * @return array
     * @throws GuzzleException
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    #[PostMapping(path: 'getServer')]
    public function getServer(): array {
        $game_hash = $this->request->post('game_hash', '');
        $openid = $this->request->post('openid', '');
        $code = $this->request->post('code', '');
        $type = $this->request->post('type', 1);
        $version = $this->request->post('version', '');

//        var_dump('登录断点start-------------');
//        var_dump($this->request->post());
//        var_dump('登录断点end-------------');
        $gameInfo = QmGameService::getGameInfo($game_hash);
        if (empty($gameInfo)) {
            return $this->buildFailed(ErrorCode::INVALID, '当前游戏不存在');
        }

        $unionId = '';
        if ($code) {
            $openid = $this->getOpenid($gameInfo, $code, $unionId, $type);
        }
        if ($openid) {
            // 获取全部生产服和维护服
            $return = [];
            $allVersion = QmGameVersion::query()->where('version', $version)->orderBy('id', 'DESC')->get();
            if ($allVersion) {
                $allGames = QmGameList::query()->where('platform', $gameInfo['platform'])->get();
                if ($allGames) {
                    $specialServer = [];
                    $allSpecial = QmGameSpecial::query()->where('openid', $openid)->first();
                    if ($allSpecial) {
                        $specialServer = explode(',', $allSpecial['game_hash']);
                    }
                    $allGames = ToolService::buildArrFromObj($allGames, 'hash');

                    foreach ($allVersion as $version) {
                        if (isset($allGames[$version['game_hash']])) {
                            if (in_array($version['status'], $this->serverStatus) || in_array($version['game_hash'], $specialServer)) {
                                $return[] = [
                                    'server_id'       => $allGames[$version['game_hash']]['id'],
                                    'name'            => $allGames[$version['game_hash']]['name'],
                                    'game_hash'       => $version['game_hash'],
                                    'status'          => $allGames[$version['game_hash']]['is_show'] == 0 ? 4 : $version['status'],
                                    'connection_code' => $version['connection_code'],
                                    'openid'          => $openid,
                                    'is_show'         => $allGames[$version['game_hash']]['is_show'],
                                    'miniapp_show'    => $allGames[$version['game_hash']]['miniapp_show'],
                                ];
                            }
                        }
                    }
                }
            }

            //这个只是补偿unionid不存在的数据，可以注释
//            if (!empty($return) && !empty($unionId)) {
//                foreach ($return as $value) {
//                    if ($value['status'] != 4) {
//                        (new GameUserInside())->setCode($value['connection_code'])->saveUnionid([
//                            'openid'    => $openid,
//                            'game_hash' => $value['game_hash'],
//                            'union_id'  => $unionId
//                        ]);
//                    }
//                }
//            }

            return $this->buildSuccess($return);
        }

        return $this->buildFailed(ErrorCode::EMPTY_PARAMS, '缺少必要参数');
    }

    /**
     * 获取唯一标识
     * @param $gameInfo
     * @param $code
     * @param $unionId
     * @param int $type
     * @return mixed|string
     * @throws GuzzleException
     */
    private function getOpenid($gameInfo, $code, &$unionId, int $type = 1): mixed {
        $openid = '';
        $client = $this->clientFactory->create(['verify' => false]);
        if (!empty($gameInfo)) {
            switch ($gameInfo['platform']) {
                case 1: // weChart
//                    $url = "https://api.weixin.qq.com/sns/jscode2session?appid={$gameInfo['app_id']}&secret={$gameInfo['app_secret']}&js_code={$code}&grant_type=authorization_code";
//                    $response = $client->get($url);
//                    $openidContent = json_decode($response->getBody()->getContents(), true);
//
//                    if (!isset($openidContent['errcode'])) {
//                        $openid = $openidContent['openid'];
//                        if (isset($openidContent['unionid']) && !empty($openidContent['unionid'])) {
//                            $unionId = $openidContent['unionid'];
//                        }
//                    }
                    $slInfo = (new SlWechatService())->loginVerify($gameInfo, $code, $type);
                    $openid = $slInfo['userid'];
                    break;
                case 2: // 抖音
                    $url = "https://minigame.zijieapi.com/mgplatform/api/apps/jscode2session?appid={$gameInfo['app_id']}&secret={$gameInfo['app_secret']}&code={$code}";
                    $response = $client->get($url);
                    $openidContent = json_decode($response->getBody()->getContents(), true);
                    if ($openidContent['error'] == 0) {
                        $openid = $openidContent['openid'];
                    }
                    break;
                case 3: // QQ
                    $url = "https://api.q.qq.com/sns/jscode2session?appid={$gameInfo['app_id']}&secret={$gameInfo['app_secret']}&js_code={$code}&grant_type=authorization_code";
                    $response = $client->get($url);
                    $openidContent = json_decode($response->getBody()->getContents(), true);
                    if (!isset($openidContent['errcode']) || $openidContent['errcode'] == 0) {
                        $openid = $openidContent['openid'];
                    }
                    break;
                case 4: // OPPO
                    $signData = [
                        'appKey'    => $gameInfo['app_id'],
                        'appSecret' => $gameInfo['app_secret'],
                        'pkgName'   => $gameInfo['app_name'],
                        'timeStamp' => time() * 1000,
                        'token'     => $code
                    ];
                    $sign = strtoupper(md5(http_build_query($signData)));
                    $url = "https://play.open.oppomobile.com/instant-game-open/userInfo?pkgName={$signData['pkgName']}&timeStamp={$signData['timeStamp']}&token={$code}&sign={$sign}";
                    $response = $client->get($url);
                    $openidContent = json_decode($response->getBody()->getContents(), true);
                    $openid = $openidContent['userInfo']['userId'];
                    break;
                case 5: // VIVO
                    $signData = [
                        'appKey'    => $gameInfo['app_id'],
                        'appSecret' => $gameInfo['app_secret'],
                        'nonce'     => (int)ToolService::randString(32, 1),
                        'pkgName'   => $gameInfo['app_name'],
                        'timestamp' => time() * 1000,
                        'token'     => $code
                    ];
                    $sign = hash('sha256', http_build_query($signData));
                    $url = "https://quickgame.vivo.com.cn/api/quickgame/cp/account/userInfo?pkgName={$signData['pkgName']}&timeStamp={$signData['timeStamp']}&token={$code}&signature={$sign}";
                    $response = $client->get($url);
                    $openidContent = json_decode($response->getBody()->getContents(), true);
                    $openid = $openidContent['data']['openId'];
                    break;
            }
        }

        return $openid;
    }

    /**
     * 测试接口 模拟业务服务器进行头像审核提交
     * @return array
     * @throws GuzzleException
     */
    #[PostMapping(path: 'checkAvatar')]
    public function checkAvatar(): array {
        return (new GameListInside())->checkAvatar();
    }

    /**
     * 更新头像任务结果
     * 接受暗夜的回调，暗夜接受微信的回调地址
     * 回调后对qm_game_wx_task表进行判断并更新 微信审核不通过的需要对用户进行去除头像和昵称的更新
     * @return array
     * @throws GuzzleException
     */
    #[PostMapping(path: 'updateAvatarTask')]
    public function updateAvatarTask(): array {
        $trace_id = $this->request->post('trace_id', '');
        $suggest = $this->request->post('suggest', '');
        if ($trace_id) {
            $model = new QmGameWxTask();
            $info = $model->where('trace_id', $trace_id)->where('status', 0)->first();
            if (!empty($info)) {
                if ($suggest == 'pass') {
                    $info->status = 1;
                } else {
                    $info->status = 2;
                    try {
                        (new PaySenderInside())->updateUserAvatar($info->game_hash, $info->version, $info->openid);
                        $info->status = 3;
                    } catch (\Exception $e) {
                        var_dump($e->getMessage());
                        $info->status = 4;
                    }
                }
                $info->save();
                return $this->buildSuccess();
            } else {
                return $this->buildFailed(ErrorCode::EMPTY_PARAMS, 'trace_id对应的任务记录不存在');
            }

        }
        return $this->buildFailed(ErrorCode::EMPTY_PARAMS, '缺少trace_id');
    }

    /**
     * 获取不同平台最新版本号
     * @return array
     * @throws GuzzleException
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    #[PostMapping(path: 'getVersion')]
    public function getVersion(): array {
        $platform = $this->request->post('platform', 0);//1 微信 2抖音
        $isTest = $this->request->post('is_test', 0);//是否是测试服，可以用来获取测试服最新版本号

        if (!is_numeric($platform) || !in_array($platform, [1, 2])) {
            return $this->buildFailed(ErrorCode::INVALID, '当前平台不存在');
        }
        if (!is_numeric($isTest) || !in_array($isTest, [0, 1])) {
            return $this->buildFailed(ErrorCode::INVALID, '参数不存在');
        }

        $redis = (ApplicationContext::getContainer())->get(RedisQueueAgent::class);
        $gameInfoRedisKey = RedisKey::GM_PLATFORM . 'GameInfo:' . $platform;
        if ($redis->exists($gameInfoRedisKey)) {
            $gameInfo = json_decode($redis->get($gameInfoRedisKey), true);
        } else {
            $gameInfo = QmGameList::query()->where('platform', $platform)->where('status', 1)->first();
            $gameInfoValue = [];
            if (!empty($gameInfo)) {
                $gameInfoValue = $gameInfo->toArray();
            }
            $redis->set($gameInfoRedisKey, json_encode($gameInfoValue), 3600);
        }
        if (empty($gameInfo)) {
            return $this->buildFailed(ErrorCode::INVALID, '当前平台不存在');
        }
        $game_hash = $gameInfo['hash'];

        if ($isTest == 1) {
            $status = [2];
        } else {
            $status = [1, 3, 5, 6, 7];
        }
        $versionRedisKey = RedisKey::GM_PLATFORM . 'GameVersion:' . $platform . ':' . $isTest;
        if ($redis->exists($versionRedisKey)) {
            $version = $redis->get($versionRedisKey);
        } else {
            $versionInfo = QmGameVersion::query()->where('game_hash', $game_hash)->whereIn('status', $status)->first();
            $version = $versionInfo->version;
            $redis->set($versionRedisKey, $version);
        }
        $return['version'] = $version ?? '';

        //app强制更新
        $appRedisKey = RedisKey::GM_PLATFORM . 'AppUpdate:' . $isTest;
        $return['app_update'] = $redis->exists($appRedisKey) ? json_decode($redis->get($appRedisKey), true) : [];

        return $this->buildSuccess($return);
    }

    /**
     * 返回指定的游戏配置
     * @return array
     * @throws \Exception
     */
    #[GetMapping(path: 'getConfig')]
    public function getConfig(): array {
        $game_hash = $this->request->query('game_hash', '651da2028476d3e669f892fba5014ebe');
        $version = $this->request->header('Version', '');
        if (empty($version)) {
            return $this->buildFailed(ErrorCode::INVALID, '当前版本不存在');
        }
        $conf_key = 'notice_info';
        $versionInfo = QmGameVersion::query()->where('status', '<>', 4)
            ->where('version', $version)
            ->where('game_hash', $game_hash)
            ->select('version', 'status', 'connection_code', 'game_hash')->first();
        if (empty($versionInfo)) {
            return $this->buildFailed(ErrorCode::INVALID, '当前版本不存在');
        }
        $res = (new GameUserInside)->setCode($versionInfo['connection_code'])->getGameVersion($game_hash, $conf_key);
        return $this->buildSuccess($res);
    }

    /**
     * 描述: 返回所有开服的游戏配置
     * 日期: 2023/5/6 11:46
     * @return array
     * @author: cinder
     */
    #[GetMapping(path: 'gameVersion')]
    public function gameVersion(): array {
        $gameHash = QmGameVersion::query()->where('status', '<>', 4)
            ->select('version', 'status', 'connection_code', 'game_hash')->get()->toArray();
        $accessToken = [
            1 => 'jnnMegFaiVkgmwJtLgFCQqXUNZCfEKDX',
            2 => 'CnrxjBNOzBdZPVvmLLZTbCtKZkSASNbG',
        ];
        if ($gameHash) {
            $gameList = QmGameList::query()->get()->toArray();
            $gamePlatform = [];
            foreach ($gameList as $value) {
                $gamePlatform[$value['hash']] = $value['platform'];
            }
            foreach ($gameHash as &$v) {
                $res = (new GameUserInside)->setCode($v['connection_code'])->getGameVersion($v['game_hash']);
                $v['access_token'] = $accessToken[$gamePlatform[$v['game_hash']]];
                $v['config'] = $res;
            }
        }
        return $this->buildSuccess($gameHash);
    }

    /**
     * 发送手机号验证码
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    #[PostMapping(path: 'sendMobile')]
    public function sendMobile(): array {
        $mobile = $this->request->post('mobile', '');
        $platform = $this->request->post('platform', '');
        $type = $this->request->post('type', 2);
        if (!in_array($type, [1, 2, 3])) {
            return $this->buildFailed(ErrorCode::INVALID, '类型不存在');
        }
        try {
            $sService = (new SmsService());
            if ($type == 2) {
                //验证绑定
                if (!in_array($platform, [1, 2])) {
                    return $this->buildFailed(ErrorCode::INVALID, '平台不存在');
                }
                $sService->checkAccount($mobile, $platform);
            }
            if ($type == 3) {
                $info = QmGameAccount::query()->where('mobile', $mobile)
                    ->get();
                if (empty($info->toArray())) {
                    return $this->buildFailed(ErrorCode::INVALID, '该手机号尚未注册，请联系游戏客服');
                }
            }
            $redis = (ApplicationContext::getContainer())->get(SmsAgent::class);
            $limitKey = RedisKey::GM_SMS . 'Limit:' . $type . ':' . $mobile;
            if ($redis->exists($limitKey)) {
                return $this->buildFailed(ErrorCode::INVALID, '短信已发送');
            }
            $res = (new SmsService())->sendSms($mobile, $type);
            if ($res['code'] == 'Ok') {
                $redis->set($limitKey, $mobile, 60);
                $verifyKey = RedisKey::GM_SMS . 'Verify:' . $type . ':' . $mobile;
                $redis->set($verifyKey, $res['data'], 300);
                return $this->buildSuccess();
            } else {
                return $this->buildFailed(ErrorCode::INVALID, '短信发送失败');
            }
        } catch (\Exception $e) {
            return $this->buildFailed($e->getCode(), $e->getMessage());
        }
    }

    /**
     * 手机号登录注册/账号登录 需要验证码
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    #[PostMapping(path: 'loginMobile')]
    public function loginMobile(): array {
        $mobile = $this->request->post('mobile', '');
        $code = $this->request->post('code', '');
        $type = $this->request->post('type', 1);
        if (empty($code)) {
            return $this->buildFailed(ErrorCode::INVALID, '请填写验证码');
        }
        try {
            $redis = (ApplicationContext::getContainer())->get(SmsAgent::class);
            $openKey = RedisKey::GM_SMS . 'Open'; //审核开关
            $open = $redis->get($openKey);
            $need_verify = 1;
            if ($type == 1) {
                $limitKey = RedisKey::GM_SMS . 'Limit:1:' . $mobile;
                $verifyKey = RedisKey::GM_SMS . 'Verify:1:' . $mobile;
                $check = $redis->get($verifyKey);
                if (empty($check)) {
                    return $this->buildFailed(ErrorCode::INVALID, '验证码不存在');
                }
                if ($check != $code) {
                    return $this->buildFailed(ErrorCode::INVALID, '验证码错误');
                }
                $info = QmGameAccount::query()->where('mobile', $mobile)
                    ->get()->toArray();
                if (empty($info)) {
                    return $this->buildFailed(ErrorCode::INVALID, '该手机号尚未绑定');
//                    $status = 1;
//                    if ($open) {
//                        $status = 3;
//                    }
//                    //手机号不存在直接注册
//                    $platform = [1, 2];
//                    $openid = $this->createOpenid();
//                    foreach ($platform as $value) {
//                        $input[] = [
//                            'mobile'     => $mobile,
//                            'openid'     => $openid,
//                            'platform'   => $value,
//                            'status'     => $status,
//                            'verify_id'  => 0,
//                            'created_at' => date('Y-m-d H:i:s'),
//                            'updated_at' => date('Y-m-d H:i:s'),
//                        ];
//                    }
//                    QmGameAccount::insert($input);
//                    $info = $input;
//                    $need_verify = 2;
                }
            } elseif ($type == 2) {
                $info = QmGameAccount::query()->where('account', $mobile)->orWhere('mobile', $mobile)
                    ->get()->toArray();
                if (empty($info)) {
                    return $this->buildFailed(ErrorCode::INVALID, '账号不存在');
                } else {
                    $pwd = ToolService::userMd5($code);
                    foreach ($info as $item) {
                        if ($item['password'] != $pwd) {
                            return $this->buildFailed(ErrorCode::INVALID, '密码不正确');
                        }
                    }
                }
            } else {
                return $this->buildFailed(ErrorCode::INVALID, '登录类型不存在');
            }
            if (str_contains($info[0]['openid'], 'YZTT')) {
                if ($open && $info[0]['status'] != 1 && $need_verify == 1) {
                    return $this->buildFailed(ErrorCode::INVALID, '该账号尚未通过审核');
                }
            }

            $return = [];
            foreach ($info as $item) {
                $age = 0;
                if ($item['verify_id'] != 0) {
                    $verifyInfo = QmGameAccountVerify::query()->where('id', $item['verify_id'])->first();
                    $age = $this->getAge($verifyInfo['idcard']);
                }
                $return[] = [
                    'openid'    => $item['openid'],
                    'platform'  => $item['platform'],
                    'status'    => 1,
                    'verify_id' => $item['verify_id'],
                    'age'       => $age,
                ];
            }
            if ($type == 1) {
                $redis->del($limitKey);
                $redis->del($verifyKey);
            }
            return $this->buildSuccess($return);
        } catch (\Exception $e) {
            return $this->buildFailed($e->getCode(), $e->getMessage());
        }
    }

    /**
     * 绑定手机号
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    #[PostMapping(path: 'bindMobile')]
    public function bindMobile(): array {
        $mobile = $this->request->post('mobile', '');
        $platform = $this->request->post('platform', '');
        $openid = trim($this->request->post('openid', ''));
        $union_id = $this->request->post('union_id', '');
        $code = $this->request->post('code', '');
        if (empty($code)) {
            return $this->buildFailed(ErrorCode::INVALID, '请填写验证码');
        }
        if (!in_array($platform, [1, 2])) {
            return $this->buildFailed(ErrorCode::INVALID, '平台不存在');
        }
        if (empty($openid) && empty($union_id)) {
            return $this->buildFailed(ErrorCode::INVALID, '请传入openid或者unionid');
        }
        $list = $this->getFindServer($platform);
        if (empty($list)) {
            return $this->buildFailed(ErrorCode::INVALID, '服务器维护中');
        }
        //抖音绑定只需要openid，微信需要通过union_id去查询
        if ($platform == 2) {
            if (empty($openid)) {
                return $this->buildFailed(ErrorCode::INVALID, '抖音绑定请传入openid');
            } else {
                $findOpenid = '';
                foreach ($list as $value) {
                    $res = (new GameUserInside())->setCode($value['connection_code'])->index([
                        'game_hash' => $value['game_hash'],
                        'openid'    => $openid
                    ]);
                    if ($res['code'] == 1 && !empty($res['data']['list'])) {
                        $findOpenid = $res['data']['list'][0]['openid'];
                        if (!empty($findOpenid)) {
                            break;
                        }
                    }
                }
                if (empty($findOpenid)) {
                    return $this->buildFailed(ErrorCode::INVALID, 'openid未找到对应用户');
                }
            }
        }
        if ($platform == 1) {
            if (!empty($union_id)) {
                $findOpenid = '';
                foreach ($list as $value) {
                    $res = (new GameUserInside())->setCode($value['connection_code'])->index([
                        'game_hash' => $value['game_hash'],
                        'union_id'  => $union_id
                    ]);
                    if ($res['code'] == 1 && !empty($res['data']['list'])) {
                        $union_id = $res['data']['list'][0]['union_id'];
                        $findOpenid = $res['data']['list'][0]['openid'];
                        if (!empty($union_id)) {
                            break;
                        }
                    }
                }
                if (empty($union_id) || empty($findOpenid)) {
                    return $this->buildFailed(ErrorCode::INVALID, 'union_id未找到对应用户');
                }
                if (!empty($openid)) {
                    if ($openid != $findOpenid) {
                        return $this->buildFailed(ErrorCode::INVALID, '传入openid和union_id找到的用户openid不一致');
                    }
                } else {
                    $openid = $findOpenid;
                }
            } elseif (!empty($openid)) {
                $findOpenid = '';
                foreach ($list as $value) {
                    $res = (new GameUserInside())->setCode($value['connection_code'])->index([
                        'game_hash' => $value['game_hash'],
                        'openid'    => $openid
                    ]);
                    if ($res['code'] == 1 && !empty($res['data']['list'])) {
                        $union_id = $res['data']['list'][0]['union_id'];
                        $findOpenid = $res['data']['list'][0]['openid'];
                        if (!empty($findOpenid)) {
                            break;
                        }
                    }
                }
                if (empty($findOpenid)) {
                    return $this->buildFailed(ErrorCode::INVALID, 'openid未找到对应用户');
                }
            }
        }

        try {
            $sService = (new SmsService());
            $sService->checkAccount($mobile, $platform);
            $redis = (ApplicationContext::getContainer())->get(SmsAgent::class);
            $limitKey = RedisKey::GM_SMS . 'Limit:2:' . $mobile;
            $verifyKey = RedisKey::GM_SMS . 'Verify:2:' . $mobile;
            $check = $redis->get($verifyKey);
            if (empty($check)) {
                return $this->buildFailed(ErrorCode::INVALID, '验证码不存在');
            }
            if ($check != $code) {
                return $this->buildFailed(ErrorCode::INVALID, '验证码错误');
            }
            $info = QmGameAccount::query()->where('mobile', $mobile)
                ->where('platform', $platform)
                ->where('openid', $openid)
                ->first();
            if (!empty($info)) {
                return $this->buildFailed(ErrorCode::INVALID, '该手机号已经绑定');
            }


            $redis->del($limitKey);
            $redis->del($verifyKey);

            $model = new QmGameAccount();
            $model->mobile = $mobile;
            $model->openid = $openid;
            $model->union_id = $union_id;
            $model->platform = $platform;
            $model->status = 1;
            $model->save();

            return $this->buildSuccess();
        } catch (\Exception $e) {
            return $this->buildFailed($e->getCode(), $e->getMessage());
        }
    }

    //获取所有需要验证的服务器
    protected function getFindServer($platform = 1): array {
        $list = [];
        $allVersion = QmGameVersion::query()->where('status', '<>', 4)->orderBy('id', 'DESC')->get();
        if ($allVersion) {
            $allGames = QmGameList::query()->where('platform', $platform)->get();
            if ($allGames) {
                $allGames = ToolService::buildArrFromObj($allGames, 'hash');

                foreach ($allVersion as $version) {
                    if (isset($allGames[$version['game_hash']])) {
                        if (in_array($version['status'], $this->serverStatus)) {
                            $list[] = [
                                'name'            => $allGames[$version['game_hash']]['name'],
                                'game_hash'       => $version['game_hash'],
                                'status'          => $allGames[$version['game_hash']]['is_show'] == 0 ? 4 : $version['status'],
                                'connection_code' => $version['connection_code'],
                                'is_show'         => $allGames[$version['game_hash']]['is_show'],
                            ];
                        }
                    }
                }
            }
        }
        return $list;
    }

    /**
     * 绑定信息查询
     * @return array
     */
    #[PostMapping(path: 'accountInfo')]
    public function accountInfo(): array {
        $openid = $this->request->post('openid', '');
        if (empty($openid)) {
            return $this->buildFailed(ErrorCode::INVALID, '请传入openid');
        }
        try {
            $info = QmGameAccount::query()->where('openid', $openid)
                ->get();
            if (empty($info)) {
                return $this->buildFailed(ErrorCode::INVALID, '账号不存在');
            }
            return $this->buildSuccess($info->toArray());
        } catch (\Exception $e) {
            return $this->buildFailed($e->getCode(), $e->getMessage());
        }
    }

    /**
     * 绑定账号注册
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    #[PostMapping(path: 'accountCreate')]
    public function accountCreate(): array {
        $account = trim($this->request->post('account', ''));
        $pwd = trim($this->request->post('password', ''));
        $confirm = trim($this->request->post('confirm', ''));
        if (empty($account) || empty($pwd) || empty($confirm)) {
            return $this->buildFailed(ErrorCode::INVALID, '缺少注册信息');
        }
        try {
            $info = QmGameAccount::query()->where('account', $account)->orWhere('mobile', $account)
                ->get();
            if (!empty($info->toArray())) {
                return $this->buildFailed(ErrorCode::INVALID, '账号已存在');
            }
            $res = $this->checkAccount($account);
            if ($res != 'pass') {
                return $this->buildFailed(ErrorCode::INVALID, $res);
            }
            if ($pwd != $confirm) {
                return $this->buildFailed(ErrorCode::INVALID, '2次输入密码不一致');
            }
            $res = $this->checkPwd($pwd);
            if ($res != 'pass') {
                return $this->buildFailed(ErrorCode::INVALID, $res);
            }

            $redis = (ApplicationContext::getContainer())->get(SmsAgent::class);
            $openKey = RedisKey::GM_SMS . 'Open'; //审核开关
            $smrzKey = RedisKey::GM_SMS . 'Smrz'; //实名认证开关
            $open = $redis->get($openKey);
            $smrz = $redis->get($smrzKey);
            $status = 1;
            if ($open) {
                $status = 3;
            }
            $verify_id = 0;
            if ($smrz) {
                $verify_id = 1;
            }

            $password = ToolService::userMd5($pwd);
            $platform = [1, 2];
            $openid = $this->createOpenid();
            foreach ($platform as $value) {
                $input[] = [
                    'account'    => $account,
                    'password'   => $password,
                    'openid'     => $openid,
                    'platform'   => $value,
                    'verify_id'  => $verify_id,
                    'status'     => $status,
                    'created_at' => date('Y-m-d H:i:s'),
                    'updated_at' => date('Y-m-d H:i:s'),
                ];
                $return[] = [
                    'openid'    => $openid,
                    'platform'  => $value,
                    'status'    => $status,
                    'verify_id' => $verify_id,
                ];
            }
            QmGameAccount::insert($input);
            return $this->buildSuccess($return);
        } catch (\Exception $e) {
            return $this->buildFailed($e->getCode(), $e->getMessage());
        }
    }

    //极低概率会有重复
    protected function createOpenid(): string {
        $str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-';
        $openid = 'YZTT-';
        $length = 20;
        for ($i = $length; $i > 0; $i--) {
            $openid .= $str[mt_rand(0, strlen($str) - 1)];
        }
        return $openid;
    }

    protected function checkPwd($candidate): string {
        if ($candidate == '') {
            return '密码不能为空';
        }
        if (strlen($candidate) < 6) {
            return "密码必须包含至少6个字符，请返回修改！";
        }
        if (strlen($candidate) > 20) {
            return "密码不能超过20个字符，请返回修改！";
        }
        if (preg_match('/[^a-zA-Z0-9]/', $candidate) > 0) {
            return "密码只能存在数字和字母，请返回修改！";
        }
        if (!preg_match('/^(?=.*[a-zA-Z])(?=.*\d).+/', $candidate)) {
            return "密码必须同时存在数字和字母，请返回修改！";
        }
        return "pass";
    }

    protected function checkAccount($candidate): string {
        if ($candidate == '') {
            return '账号不能为空';
        }
        if (strlen($candidate) < 6) {
            return "账号必须包含至少6个字符，请返回修改！";
        }
        if (strlen($candidate) > 20) {
            return "账号不能超过20个字符，请返回修改！";
        }
        if (is_numeric($candidate)) {
            return "账号不能为纯数字，请返回修改！";
        }
        if (preg_match('/[^a-zA-Z0-9]/', $candidate) > 0) {
            return "账号只能存在数字和字母，请返回修改！";
        }
        return "pass";
    }

    /**
     * 实名认证
     * @return array
     * @throws GuzzleException
     */
    #[PostMapping(path: 'smrz')]
    public function smrz(): array {
        $idcard = trim($this->request->post('idcard', ''));
        $name = trim($this->request->post('name', ''));
        $openid = trim($this->request->post('openid', ''));
        if (empty($name) || empty($idcard) || empty($openid)) {
            return $this->buildFailed(ErrorCode::INVALID, '缺少实名认证信息');
        }
        try {
            $age = $this->getAge($idcard);
            if ($age < 18) {
                return $this->buildFailed(ErrorCode::INVALID, '未成年无法实名认证');
            }
            $checkId = $this->checkIdcard($idcard);
            if (!$checkId) {
                return $this->buildFailed(ErrorCode::INVALID, '身份证格式不正确');
            }
            if (!preg_match("/^[\x{4e00}-\x{9fa5}]{2,6}$/u", $name)) {
                return $this->buildFailed(ErrorCode::INVALID, '姓名格式不正确');
            }
            $info = QmGameAccount::query()->where('openid', $openid)
                ->where('verify_id', 0)
                ->get();
            if (empty($info->toArray())) {
                return $this->buildFailed(ErrorCode::INVALID, '该openid不存在或已经实名认证过');
            }
//            $verifyInfo = QmGameAccountVerify::query()->where('openid', $openid)
//                ->get();
//            if (!empty($verifyInfo->toArray())) {
//                return $this->buildFailed(ErrorCode::INVALID, '该openid已经实名认证过');
//            }
            $res = (new AliyunService())->check($idcard, $name);
            if ($res['code'] != 0) {
                return $this->buildFailed(ErrorCode::INVALID, '实名认证失败');
            }
            if ($res['result']['res'] != 1) {
                return $this->buildFailed(ErrorCode::INVALID, '实名认证结果' . $res['result']['description']);
            }
            $input = [
                'openid'     => $openid,
                'idcard'     => $idcard,
                'name'       => $res['result']['name'],
                'sex'        => $res['result']['sex'],
                'birthday'   => $res['result']['birthday'],
                'address'    => $res['result']['address'],
                'created_at' => date('Y-m-d H:i:s'),
                'updated_at' => date('Y-m-d H:i:s'),
            ];
            $id = QmGameAccountVerify::insertGetId($input);
            QmGameAccount::query()->where('openid', $openid)->update(['verify_id' => $id]);

            return $this->buildSuccess();
        } catch (GuzzleException $e) {
            return $this->buildFailed($e->getCode(), $e->getMessage());
        }
    }

    //根据身份证获取年龄
    protected function getAge($idNo = 0): int {
        // 1.从身份证中获取出生日期
        $id = $idNo;//身份证
        $birth_Date = strtotime(substr($id, 6, 8));//截取日期并转为时间戳

        //2.格式化[出生日期]
        $Year = date('Y', $birth_Date);//yyyy
        $Month = date('m', $birth_Date);//mm
        $Day = date('d', $birth_Date);//dd

        // 3.格式化[当前日期]
        $current_Y = date('Y');//yyyy
        $current_M = date('m');//mm
        $current_D = date('d');//dd

        // 4.计算年龄()
        $age = $current_Y - $Year;//今年减去生日年
        if ($Month > $current_M || $Month == $current_M && $Day > $current_D) {//深层判断(日)
            $age--;//如果出生月大于当前月或出生月等于当前月但出生日大于当前日则减一岁
        }
        return $age;

    }

    //检查身份证
    protected function checkIdcard($id_card): bool {
        $preg = "/^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/";
        if (preg_match($preg, $id_card)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 修改密码 只支持旧密码
     * @return array
     */
    #[PostMapping(path: 'updatePassword')]
    public function updatePassword(): array {
        $openid = trim($this->request->post('openid', ''));
        $old = trim($this->request->post('old_password', ''));
        $new = trim($this->request->post('new_password', ''));
        $confirm = trim($this->request->post('confirm_password', ''));
        if (empty($openid) || empty($old) || empty($new) || empty($confirm)) {
            return $this->buildFailed(ErrorCode::INVALID, '缺少参数');
        }
        try {
            $info = QmGameAccount::query()->where('openid', $openid)
                ->get();
            if (empty($info->toArray())) {
                return $this->buildFailed(ErrorCode::INVALID, '该账号不存在');
            }
            $res = $this->checkPwd($new);
            if ($res != 'pass') {
                return $this->buildFailed(ErrorCode::INVALID, $res);
            }

            $oldPwd = ToolService::userMd5($old);
            $newPwd = ToolService::userMd5($new);
            $confirmPwd = ToolService::userMd5($confirm);
            if ($confirmPwd != $newPwd) {
                return $this->buildFailed(ErrorCode::INVALID, '两次输入密码不一致');
            }
            foreach ($info as $item) {
                if ($item['password'] != $oldPwd) {
                    return $this->buildFailed(ErrorCode::INVALID, '旧密码不正确');
                }
            }
            QmGameAccount::query()->where('openid', $openid)
                ->update(['password' => $newPwd]);

            return $this->buildSuccess();
        } catch (Exception $e) {
            return $this->buildFailed($e->getCode(), $e->getMessage());
        }
    }

    /**
     * 设定密码和重置密码 只支持手机号
     * @return array
     */
    #[PostMapping(path: 'resetPassword')]
    public function resetPassword(): array {
        $mobile = trim($this->request->post('mobile', ''));
        $code = trim($this->request->post('code', ''));
        $new = trim($this->request->post('new_password', ''));
        $confirm = trim($this->request->post('confirm_password', ''));
        if (empty($mobile) || empty($new) || empty($confirm)) {
            return $this->buildFailed(ErrorCode::INVALID, '缺少参数');
        }
        if (empty($code)) {
            return $this->buildFailed(ErrorCode::INVALID, '请填写验证码');
        }

        try {
            $info = QmGameAccount::query()->where('mobile', $mobile)
                ->get();
            if (empty($info->toArray())) {
                return $this->buildFailed(ErrorCode::INVALID, '该手机号尚未注册，请联系游戏客服');
            }
            //验证码验证
            $redis = (ApplicationContext::getContainer())->get(SmsAgent::class);
            $limitKey = RedisKey::GM_SMS . 'Limit:3:' . $mobile;
            $verifyKey = RedisKey::GM_SMS . 'Verify:3:' . $mobile;
            $check = $redis->get($verifyKey);
            if (empty($check)) {
                return $this->buildFailed(ErrorCode::INVALID, '验证码不存在');
            }
            if ($check != $code) {
                return $this->buildFailed(ErrorCode::INVALID, '验证码错误');
            }
            //密码验证
            $res = $this->checkPwd($new);
            if ($res != 'pass') {
                return $this->buildFailed(ErrorCode::INVALID, $res);
            }
            $newPwd = ToolService::userMd5($new);
            $confirmPwd = ToolService::userMd5($confirm);
            if ($confirmPwd != $newPwd) {
                return $this->buildFailed(ErrorCode::INVALID, '两次输入密码不一致');
            }

            $redis->del($limitKey);
            $redis->del($verifyKey);

            QmGameAccount::query()->where('mobile', $mobile)
                ->update(['password' => $newPwd]);

            return $this->buildSuccess();
        } catch (Exception $e) {
            return $this->buildFailed($e->getCode(), $e->getMessage());
        }
    }

}